#pragma once

#include "utility.hpp"

namespace zuck 
{
	struct _Color {
		static inline zuck::size_t constexpr red    = 0;
		static inline zuck::size_t constexpr black  = 1;
		static inline zuck::size_t constexpr dblack = 2;
	};

	template<bool multi, typename T>
	class __tree_node;
	template<typename T>
	class __tree_node<false, T> {
		static_assert(!is_void_v<T>, 
			"template parameter \"T\" couldn't be incomplete type");
	public:
		using color_t       = zuck::size_t;
		using value_type	= T;
		using pointer		= T*;
		using const_pointer = const T*;
		using reference		= T&;
	private:
		using _Self		= __tree_node<false, T>;
		using _Node_ptr = __tree_node<false, T>*;
		using _Data_ptr = T*;
	public:
		pointer	  __d;
		_Node_ptr _m_p;
		_Node_ptr __l;
		_Node_ptr __r;
		color_t   __col;
	public:
		explicit __tree_node()noexcept
			: __d(), _m_p(), __l(), __r(), __col(_Color::black) {}

		explicit __tree_node(T* Valty, zuck::size_t _t = _Color::red, 
			_Node_ptr _p = null, _Node_ptr _l = null, _Node_ptr _M_r = null)
			: __d(Valty), __col(_t), _m_p(_p), __l(_l), __r(_M_r) {}

		inline ~__tree_node()noexcept
		{
			__d	= null;
			_m_p	= null;
			__l	= null;
			__r	= null;
		}

		[[nodiscard]] static inline _Node_ptr
		_Allocate(pointer data, color_t col, _Node_ptr parent, _Node_ptr left = null, _Node_ptr right = null)
		{
			return new __tree_node<false, T>(data, col, parent, left, right);
		}

		static void _Deallocate(_Node_ptr ptr)
		{
			if (ptr) {
				delete ptr;
			}
		}

	public:
		__tree_node(_Self const&) = delete;
		__tree_node(_Self&&)	  = delete;

		_Self& operator=(_Self const&) = delete;
		_Self& operator=(_Self&&)	   = delete;
	};

	template<typename T>
	class __tree_node<true, T> {
		static_assert(!is_void_v<T>, 
			"template parameter \"T\" couldn't be incomplete type");
	public:
		using value_type	= T;
		using pointer		= T*;
		using const_pointer = T const*;
		using reference		= T&;
		using color_t		= zuck::size_t;
	private:
		using _Self		= __tree_node<false, T>;
		using _Node_ptr = __tree_node<false, T>*;
	public:
		pointer   __d;
		_Node_ptr _m_n;
		_Node_ptr _m_p;
		_Node_ptr __l;
		_Node_ptr __r;
		color_t   __col;
	public:
		explicit __tree_node()noexcept
			: __d() , __col(_Color::black), _m_n(), _m_p(), __l(), __r() {}

		explicit __tree_node(pointer data, zuck::size_t color = _Color::red, 
			_Node_ptr n = null, _Node_ptr p = null, _Node_ptr l = null, _Node_ptr r = null)
			: __d(data), __col(color), _m_n(n), _m_p(p), __l(l), __r(r) {}

		inline ~__tree_node()noexcept
		{
			__d = null;
			_m_n = null;
			_m_p = null;
			__l = null;
			__r = null;
		}

		[[nodiscard]] static _Node_ptr 
		_Allocate(pointer data, _Color cor, _Node_ptr n, _Node_ptr p = null, _Node_ptr l = null, _Node_ptr r = null)
		{
			return new __tree_node<true, T>(data, cor, n, p, l, r);
		}

		static void _Deallocate(_Node_ptr ptr)
		{
			if (ptr) {
				delete ptr;
			}
		}

	public:
		__tree_node(_Self const&)	= delete;
		__tree_node(_Self&&)		= delete;

		_Self& operator=(_Self const&)	= delete;
		_Self& operator=(_Self&&)		= delete;
	};
}